<?php

namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;
use App\Http\Controllers\AdminController;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class SecKillController extends AdminController
{   
    protected $number = '';                      // 抢购商品数
    protected $waitKey = 'userWait';            // 等待用户，防止同一用户重复抢
    protected $buyKey = 'userBuy';              // 抢购成功用户
    protected $goodsKey = 'user_list';         // 抢购商品
    //将库存加入列队
    public function AddUserToRedis() {
        $first = DB::table('ih_store')->where('goods_id',1)->first();
        $this->number = $first->number;
        //Redis::set('cs',22);
        $user_num = Redis::llen($this->goodsKey);
        if($user_num){
            echo '库存已经存在！';
        }else{
            for ($i = 0; $i < $this->number; $i++) {
                try {
                    Redis::lpush($this->goodsKey, rand(1, 10000));
                } catch (Exception $e) {
                    echo $e->getMessage();
                }
            }
        }
        //Redis::del('user_list');
        dd(Redis:: lrange($this->goodsKey,0,-1));
    }
    /**
     * D:\phpStudy\PHPTutorial\Apache\bin
     * ab -n 1200 -c 200 http://www.laravel.com/admin/SecKillTest
     * 向我们的程序发起1200个请求，并发量为200
     */
    public function SecKillTest() {//在此之前我们已经将一千过用户写入了redis中了
        $uid = mt_rand(10000,99999);//dd(Redis:: lrange($this->goodsKey,0,-1));die;
        $repeatRes = Redis::hset($this->waitKey,$uid,$uid);//防止用户重复抢，如果已抢这里返回值是0，否则返回1
        //dd(Redis::hkeys($this->waitKey));die;
        $count=Redis::lpop($this->goodsKey);//lpop是移除并返回列表的第一个元素
        if(!$count){
            echo '已经抢光了哦';
        }else{
            if ($repeatRes == 1){
                $this->AddGoodToRedis(1);//需要注意的是我们如果写的是秒杀活动的话，需要做进一步的处理，例如设置商品队列的缓存等方式，这里就实现了　　　　　　　///下订单减库存
                $this->GetGood(1,$count);
                echo "抢购成功了哦";
            //生成订单之后进入支付页面...
            }else{ 
                echo '不要再来了，给别人留点吧'; 
            }
        }
      }
    /**
     * 重点在于Redis中存储数据的单线程的原子性，！！！无论多少请求同时执行这个方法，依然是依次执行的！！！！！
     * 这种方式性能较高，并且确保了对数据库的单一操作，但容错率极低，一旦出现未可预知的错误会导致数据混乱；
     * $id商品id user_id用户id
     */

    public function GetGood($id,$user_id) {
        $good = DB::table('ih_goods')->where('goods_id',$id)->first();
        $first = DB::table('ih_store')->where('goods_id',$good->goods_id)->first();
        if (is_null($good)) {
            $this->DoLog("商品不存在");
            return 'error';
        }
        ///去除一个库存
        $num = Redis::lpop('good_list');
        DB::beginTransaction();
        ///判断取出库存是否成功
        if (!$num) {
            $this->DoLog("取出库存失败");
            return 'error';
        } else {
            try{
                ///创建订单
                $data['order_sn']= rand(999,9999);
                $data['user_id'] = $user_id;
                $data['goods_id'] = $good->goods_id;
                $data['price'] =100;
                $data['addtime'] =date('Y-m-d H:i:s');
                DB::table('ih_order')->insert($data);//生成订单
                $ok = DB::table('ih_store')
                        ->where('id', $first->id)
                        ->decrement('number', $num);
                if ($ok) {
                    // 提交事务
                    DB::commit();
                    echo'下单成功';
                } else {
                    DB::rollBack();
                    $this->DoLog("库存减少失败");
                }
            }catch(Exception $e){
                // 出错回滚数据
                DB::rollBack();
                return 'error';
            }
            
        }
    }
    /**
     * $id  商品id
     */
    public function AddGoodToRedis($id) {
        $good = DB::table('ih_goods')->where('goods_id',$id)->first();
        $first = DB::table('ih_store')->where('goods_id',$good->goods_id)->first();
        if ($good == null) {
            $this->DoLog("商品不存在");
            return;
        }
        ///获取当前redis中的库存。
        $left = Redis::llen('good_list');
        ///获取到当前实际存在的库存，库存减去Redis中剩余的数量。
        $count = $first->number - $left;
        //        dd($good->good_left);
        ///将实际库存添加到Redis中
        for ($i = 0; $i < $count; $i++) {
            Redis::lpush('good_list', 1);
        }
        echo Redis::llen('good_list');
    }
    // public function getGood4Mysql($id) {
    //     DB::beginTransaction();
    //     ///开启事务对库存以及下单进行处理
    //     try {
    //         ///创建订单
    //         $order = new \App\Order();
    //         $order->good_id = $good->good_id;
    //         $order->user_id = rand(1, 1000);
    //         $order->save();
    //         $good = DB::table("goods")->where(['goods_id' => $id])->sharedLock()->first();
    //         //对商品表进行加锁(悲观锁)
    //         if ($good->good_left) {
    //             $ok = DB::table('Goods')
    //                     ->where('good_id', $good->good_id)
    //                     ->decrement('good_left', $num);
    //             if ($ok) {
    //                 // 提交事务
    //                 DB::commit();
    //                 echo'下单成功';
    //             } else {
    //                 $this->DoLog("库存减少失败");
    //             }
    //         } else {
    //             $this->DoLog("库存剩余为空");
    //         }
    //         DB::rollBack();
    //         return 'error';
    //     } catch (Exception $e) {
    //         // 出错回滚数据
    //         DB::rollBack();
    //         return 'error';
    //         //执行其他操作
    //     }
    // }
    public function DoLog() {
        $log = Redis::hkeys($this->waitKey);dd($log);die;
        $log = json_encode($log);
        $res = file_put_contents("/data/test.txt", $log . '\r\n', FILE_APPEND);
        if($res){
            Redis::del($this->waitKey);
        }
        
        dd(FILE_APPEND);die;
    }
}
